/*
* Copyright (c)  2017, ueboot.com
* All rights reserved.
* 2017-10-29 11:39:14
*/
package com.ueboot.weishop.api.controller.order;

import com.alibaba.fastjson.JSON;
import com.ueboot.core.exception.BusinessException;
import com.ueboot.core.http.response.Response;
import com.ueboot.weishop.api.SessionUtils;
import com.ueboot.weishop.api.component.OrderProcesser;
import com.ueboot.weishop.api.controller.order.vo.*;
import com.ueboot.weishop.api.controller.weixin.WeixinPayNoticeController;
import com.ueboot.weishop.api.mq.config.QueuesType;
import com.ueboot.weishop.entity.activity.ActivityEntity;
import com.ueboot.weishop.entity.goods.GoodsInfoEntity;
import com.ueboot.weishop.entity.order.*;
import com.ueboot.weishop.service.activity.ActivityService;
import com.ueboot.weishop.service.cache.CacheService;
import com.ueboot.weishop.service.goods.GoodsInfoService;
import com.ueboot.weishop.service.order.OrderExtensionService;
import com.ueboot.weishop.service.order.OrderInvoiceService;
import com.ueboot.weishop.service.order.OrderReceiverService;
import com.ueboot.weishop.service.order.OrderService;
import com.ueboot.weishop.service.weixin.WXUnifiedOderReq;
import com.ueboot.weishop.service.weixin.WXUnifiedOderResp;
import com.ueboot.weishop.service.weixin.WeiXinService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.util.Assert;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.Date;


/**
 * Created by yangkui  on 2017-10-29 11:39:14.
 * 订单接口
 * - 下订单
 * - 查询订单
 * - 修改订单
 * - 删除订单
 *
 * @author yangkui
 * @since 2.0 by autocode
 */
@Slf4j
@RestController
@RequestMapping(value = "/api/private/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private OrderInvoiceService orderInvoiceService;

    @Autowired
    private OrderReceiverService orderReceiverService;

    @Autowired
    private OrderExtensionService orderExtensionService;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private GoodsInfoService goodsInfoService;

    @Autowired
    private CacheService cacheService;

    @Autowired
    private WeiXinService weiXinService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Autowired
    private OrderProcesser orderProcesser;

    /**
     * 下订单，针对秒正常购买活动的商品进行下单。成功后直接返回订单号，可以进行支付
     * - 查询当前用户这个活动这个商品是否已经购买过，比对活动设置的可以重复购买的规则
     * - 查询当前购买的商品对应的活动是否处于正常时间范围内
     * - 分配库存序号，校验是否大于总库存数或者总库存数加回滚库存数
     * - 生成订单到DB和cache当中
     * - 提交微信订单支付
     */
    @RequestMapping(value = "/submitOrder", method = RequestMethod.POST)
    public Response<OrderResp> submitOrder(@RequestBody OrderReq req) {
        String openId = SessionUtils.getOpenId();
        ActivityEntity act = orderProcesser.checkSubmitReq(req, openId);
        String keyForLimit = orderProcesser.getKeyForLimit(act, openId, req);
        //活动统计缓存key值
        String actCountCacheKey = act.getSn() + ":" + act.getId();
        //是否允许购买
        boolean allowBuy = false;

        String json = goodsInfoService.findById(req.getGoodsInfoId());
        if (json == null) {
            cacheService.incrActOrderError(actCountCacheKey);
            throw new BusinessException("1041", "商品信息不存在！");
        }
        GoodsInfoEntity goods = JSON.parseObject(json, GoodsInfoEntity.class);
        orderProcesser.getPayAmountAndLimitCount(actCountCacheKey, act, goods, req);
        //限购的库存数
        Integer limitCount = req.getLimitCount();
        //支付金额
        Integer payAmount = req.getPayAmount();
        //已经购买的数量
        Integer alreadyBuyCount = cacheService.getAlreadyBuyCount(actCountCacheKey, req.getCountKey());
        log.info("当前活动:{}已经购买的数量:{}", act.getName(), alreadyBuyCount);
        //4.检查现在已经购买的数量和商品可购买数量是否允许购买
        if (limitCount != null && alreadyBuyCount != null && alreadyBuyCount > limitCount) {
            // 回滚库存判断，从回滚的库存队列当中获取一个资格，如果有则继续允许
            String rollbackOrder = cacheService.popRollbackOrder(actCountCacheKey);
            if (rollbackOrder != null) {
                log.info("从回滚库存当中获取到购买资格，回滚的订单号:{}", rollbackOrder);
                allowBuy = true;
            } else {
                cacheService.incrActOrderFail(actCountCacheKey);
                throw new BusinessException("106", "当前选择的商品库存不足！");
            }
        }

        //5.分配库存序号
        Long orderIndex = cacheService.incrAlreadyBuyCount(actCountCacheKey, req.getCountKey(), Long.valueOf(req.getGoodsInfoCount()));

        //校验是否已经大于库存数
        if (!allowBuy) {
            if (limitCount != null && orderIndex > limitCount) {
                cacheService.incrActOrderFail(actCountCacheKey);
                throw new BusinessException("107", "当前选择的商品库存不足！");
            }
        }
        //6.进行下单操作
        String orderNo = orderService.getOrderNo();

        log.info("openId:{},keyForLimit:{}下订单，订单号：{}", openId, keyForLimit, orderNo);
        req.setLimitCount(limitCount);
        req.setPayAmount(payAmount);
        req.setKeyForLimit(keyForLimit);
        req.setOpenId(openId);
        req.setOrderNo(orderNo);
        OrderEntity order = orderProcesser.saveOrder(req, act, goods);
        //保存订单数据到缓存当中
        cacheService.putOrder(act, order);
        cacheService.incrActOrderSuccess(actCountCacheKey);
        OrderResp resp = new OrderResp();
        resp.setOrderNo(orderNo);
        log.info("订单保存到Cache成功,orderNo:{}", orderNo);
        return new Response<>(resp);
    }


    /**
     * 异步提交订单，订单提交后会进入MQ队列进行异步处理，前端会获取到一个唯一标识号
     * 页面需要进行轮询查询该唯一标识号的状态（queryOrderStatus）,只有下单成功的标识号才
     * 进行下一步支付动作。
     *
     * @param req 订单信息
     * @return 请求唯一标识号
     */
    @RequestMapping(value = "/submitOrderSync", method = RequestMethod.POST)
    public Response<OrderResp> submitOrderSync(@RequestBody OrderReq req) {
        String openId = SessionUtils.getOpenId();
        ActivityEntity act = orderProcesser.checkSubmitReq(req, openId);
        String keyForLimit = orderProcesser.getKeyForLimit(act, openId, req);
        //活动统计缓存key值
        String actCountCacheKey = act.getSn() + ":" + act.getId();

        String json = goodsInfoService.findById(req.getGoodsInfoId());
        if (json == null) {
            cacheService.incrActOrderError(actCountCacheKey);
            throw new BusinessException("1041", "商品信息不存在！");
        }
        GoodsInfoEntity goods = JSON.parseObject(json, GoodsInfoEntity.class);
        orderProcesser.getPayAmountAndLimitCount(actCountCacheKey, act, goods, req);
        //限购的库存数
        Integer limitCount = req.getLimitCount();

        //本次活动已经购买的数量
        Integer alreadyBuyCount = cacheService.getAlreadyBuyCount(actCountCacheKey, req.getCountKey());
        log.info("当前活动:{}已经购买的数量:{}", act.getName(), alreadyBuyCount);
        //检查现在已经购买的数量和商品可购买数量是否允许购买
        if (limitCount != null && alreadyBuyCount != null && alreadyBuyCount > limitCount) {
            // 从回滚的库存队列当中获取回滚数量，如果回滚的库存数量也不足时，提示无法购买
            Long rollbackOrder = cacheService.countRollbackOrder(actCountCacheKey+":"+req.getCountKey());
            log.info("回滚库存可以购买数量:{},key:{}",rollbackOrder,actCountCacheKey+":"+req.getCountKey());
            if (rollbackOrder < req.getGoodsInfoCount()) {
                cacheService.incrActOrderFail(actCountCacheKey);
                throw new BusinessException("106", "当前需要购买的商品库存不足！");
            }
        }
        //分配唯一标识号给本次请求，然后开始进行异步下单处理
        String requestId = cacheService.getRequestId(actCountCacheKey);
        req.setRequestId(requestId);
        req.setKeyForLimit(keyForLimit);
        req.setOpenId(openId);
        amqpTemplate.convertAndSend(QueuesType.ORDER_SUBMIT_SYNC, JSON.toJSONString(req));
        log.info("已提交下单请求到mq,requestId:{}",requestId);
        OrderResp resp = new OrderResp();
        resp.setRequestId(requestId);
        return new Response<>(resp);
    }


    /**
     * 获取微信支付信息调用接口
     *
     * @param req 请求入参对象
     * @return
     */
    @RequestMapping(value = "/payInfo", method = RequestMethod.POST)
    public Response<OrderPayResp> payInfo(@RequestBody OrderPayReq req) {

        String openId = SessionUtils.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "请使用微信下单");
        }

        OrderPayResp resp = new OrderPayResp();
        OrderEntity order = orderService.findByOrderNo(req.getOrderNo());
        if(order==null){
            throw new BusinessException("订单不存在！");
        }
        if (!order.getCustomerOpenId().equals(SessionUtils.getOpenId())) {
            throw new BusinessException("200", "当前请求的openId与订单数据不一致!");
        }
        if (!OrderEnum.ORDER_STATUS_0.equals(order.getOrderStatus())) {
            throw new BusinessException("201", "订单非待支付状态，不能重复支付！");
        }

        boolean compare = orderProcesser.compare(new Date(), order.getPayValidTime()) > 0;
        if (compare) {
            throw new BusinessException("202", "支付时间已过，订单已失效！");
        }

        WXUnifiedOderReq wxReq = new WXUnifiedOderReq();
        wxReq.setCustomerIp("127.0.0.1");
        wxReq.setCustomerOpenId(SessionUtils.getOpenId());
        wxReq.setOrderId(order.getId());
        wxReq.setOrderNo(order.getOrderNo());
        //订单金额（分）
        wxReq.setOrderPrice(order.getPayAmount());
        wxReq.setProductName(order.getGoodsName());
        wxReq.setPaymentChannel("");
        wxReq.setAttach(WeixinPayNoticeController.ORDER_ATTACH);
        //返回微信支付需要的参数
        //微信统一下单接口
        WXUnifiedOderResp wxResp = null;
        try {
            wxResp = weiXinService.unifiedOrder(wxReq);
        } catch (BusinessException e) {
            log.error("订单支付失败！", e);
            throw new BusinessException("204", "订单支付失败，系统异常！");
        }
        if (wxResp == null) {
            log.error("订单支付失败！");
            throw new BusinessException("203", "订单支付失败，系统异常！");
        }
        if (!StringUtils.isEmpty(wxResp.getErrorMsg())) {
            resp.setMessage(wxResp.getErrorMsg());
            resp.setFlag(false);
        } else {
            resp.setWxResp(wxResp);
            resp.setFlag(true);
            resp.setOrderNum(order.getOrderNo());
            resp.setVin(order.getKeyForLimit());
            resp.setOrderId(order.getId());
        }
        return new Response<>(resp);
    }


    /**
     * 支付确认，前台微信支付成功后，将支付状态改为支付中，等待支付回调变为支付成功！
     * 同时在Redis当中增加成功的订单数据
     *
     * @param req 请求入参对象
     * @return
     */
    @RequestMapping(value = "/orderPayConfirm", method = RequestMethod.POST)
    public Response<Void> orderPayConfirm(@RequestBody OrderPayReq req) {
        String openId = SessionUtils.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "请使用微信下单");
        }
        OrderEntity order = orderService.findByOrderNo(req.getOrderNo());
        if (!OrderEnum.ORDER_STATUS_0.equals(order.getOrderStatus())) {
            throw new BusinessException("101", "订单非待支付状态，无法设置为支付中！");
        }
        orderService.updateOrderStatus(req.getOrderNo(), OrderEnum.ORDER_STATUS_1);
        return new Response<Void>();
    }


    @RequestMapping(value = "/delete", method = RequestMethod.POST)
    public Response<Void> delete(Long[] id) {
        String openId = SessionUtils.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "请使用微信下单");
        }
        orderService.delete(id);
        return new Response<>();
    }

    @RequestMapping(value = "/queryRequestIdStatus", method = RequestMethod.POST)
    public Response<OrderResp> queryRequestIdStatus(@RequestBody OrderQueryReq req) {
        String status = cacheService.queryRequestIdStatus(req.getRequestId());
        OrderResp resp = new OrderResp();
        resp.setRequestStatus(status);
        return new Response<>(resp);
    }


    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public Response<OrderResp> get(@PathVariable Long id) {
        String openId = SessionUtils.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "请使用微信下单");
        }
        OrderEntity entity = orderService.get(id);
        OrderResp resp = new OrderResp();
        BeanUtils.copyProperties(entity, resp);
        return new Response<>(resp);
    }


    @RequestMapping(value = "/{status}/{orderNo}", method = RequestMethod.POST)
    public Response<OrderDetailResp> detail(@PathVariable String status, @PathVariable String orderNo) {
        log.info("url:{},orderNo:{}",status,orderNo);
        String openId = SessionUtils.getOpenId();
        if (StringUtils.isEmpty(openId)) {
            throw new BusinessException("000", "请使用微信下单");
        }

        OrderEntity order = orderService.findByOrderNo(orderNo);
        if(order==null){
            throw new BusinessException("订单不存在！");
        }
        if (!SessionUtils.getOpenId().equals(order.getCustomerOpenId())) {
            throw new BusinessException("300", "当前请求的openId与订单数据不一致!");
        }
        if (status.equals("unpaid") && !OrderEnum.ORDER_STATUS_0.equals(order.getOrderStatus())) {
            throw new BusinessException("301", "订单非待支付状态，不能重复支付！");
        }

        if (status.equals("paid") && !OrderEnum.ORDER_STATUS_2.equals(order.getOrderStatus())) {
            throw new BusinessException("302", "订单状态不正确！");
        }
        OrderDetailResp resp = new OrderDetailResp();


        //订单详情
        OrderExtensionEntity extensionEntity = orderExtensionService.findByOrderNo(orderNo);
        if (extensionEntity != null) {
            BeanUtils.copyProperties(extensionEntity, resp);
        }
        //折扣
        if (!StringUtils.isEmpty(order.getActivitySN())) {
            ActivityEntity activityEntity = activityService.findBySn(order.getActivitySN());
            if (activityEntity != null) {
                if (activityEntity.getDiscountValue() != null) {
                    resp.setDiscountValue(activityEntity.getDiscountValue());
                }
                if (activityEntity.getDiscountMinusPrice() != null) {
                    resp.setDiscountMinusPrice(activityEntity.getDiscountMinusPrice() / 100);
                }
            }
        }
        //发票
        if (order.getNeedInvoice()) {
            OrderInvoiceEntity invoiceEntity = orderInvoiceService.findByOrderOrderNo(orderNo);
            if (invoiceEntity != null) {
                resp.setInvoiceType(invoiceEntity.getInvoiceType());
                resp.setTaxFileNumber(invoiceEntity.getTaxFileNumber());
                resp.setTitleName(invoiceEntity.getTitleName());
            }

            OrderReceiverEntity receiverEntity = orderReceiverService.findByOrderOrderNo(orderNo);
            if (receiverEntity != null) {
                resp.setAddress(receiverEntity.getAddress());
                resp.setAreaFullName(receiverEntity.getAreaFullName());
                resp.setAreaName(receiverEntity.getAreaName());
                resp.setCityName(receiverEntity.getCityName());
                resp.setConsignee(receiverEntity.getConsignee());
                resp.setZipCode(receiverEntity.getZipCode());
                resp.setProvinceName(receiverEntity.getProvinceName());
            }
        }


        BeanUtils.copyProperties(order, resp);
        if (order.getPayAmount() != null) {
            resp.setPayAmount(order.getPayAmount() / 100d);
        }
        if (order.getOriginalPrice() != null) {
            resp.setOriginalPrice(resp.getOriginalPrice() / 100);
        }
        return new Response<>(resp);
    }



}
